#include "capture.h"
#include <stdio.h>
#include <jpeglib.h>

// 初始化抓拍状态
void capture_state_init(CaptureInfo_S *state) {
    memset(state, 0x0, sizeof(CaptureInfo_S));
    state->lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
    // Use default values similar to load_snap_info_from_ini
    state->CaptureInfo.timing_snap_enable = 0;
    state->CaptureInfo.timing_snap.image_format = 0;
    state->CaptureInfo.timing_snap.resolution = 0;
    state->CaptureInfo.timing_snap.interval = 1;
    state->CaptureInfo.timing_snap.quality = 0;
    state->CaptureInfo.timing_snap.num = 1;
    // Optionally, load from INI here if desired, but defaults are safer for init
    // load_snap_info_from_ini(&state->CaptureInfo);
}

// 设置抓拍配置
void set_capture_config(CaptureInfo_S *state, const NetworkConfigStorageSnapParam *new_config) {
    pthread_mutex_lock(&state->lock);
    memcpy(&state->CaptureInfo, new_config, sizeof(NetworkConfigStorageSnapParam));
    pthread_mutex_unlock(&state->lock);
}

// 获取抓拍配置
NetworkConfigStorageSnapParam get_capture_config(CaptureInfo_S *state) {
    NetworkConfigStorageSnapParam config;
    pthread_mutex_lock(&state->lock);
    memcpy(&config, &state->CaptureInfo, sizeof(NetworkConfigStorageSnapParam));
    pthread_mutex_unlock(&state->lock);
    return config;
}

int yuv_to_bgr_packet(VIDEO_FRAME_INFO_S *FrameInfo, unsigned char *dst)
{
    HI_S32 s32Ret;
    HI_U32 u32DstBlkSize;
    IVE_CSC_CTRL_S stCscCtrl;
    HI_BOOL bInstant = HI_TRUE;
    HI_BOOL bFinish;
    IVE_HANDLE IveHandle;


    IVE_SRC_IMAGE_S stSrc_nv12_packet;
    IVE_DST_IMAGE_S stDst_bgr_packet;

    stSrc_nv12_packet.enType = IVE_IMAGE_TYPE_YUV420SP;
    stDst_bgr_packet.enType = IVE_IMAGE_TYPE_U8C3_PACKAGE;
    stCscCtrl.enMode = IVE_CSC_MODE_PIC_BT709_YUV2RGB;

    u32DstBlkSize = FrameInfo->stVFrame.u32Stride[0] * FrameInfo->stVFrame.u32Height * 3;

    stDst_bgr_packet.au32Stride[0] = FrameInfo->stVFrame.u32Stride[0];
    stDst_bgr_packet.u32Width = FrameInfo->stVFrame.u32Width;
    stDst_bgr_packet.u32Height = FrameInfo->stVFrame.u32Height;

    stSrc_nv12_packet.au64PhyAddr[0] = FrameInfo->stVFrame.u64PhyAddr[0];
    stSrc_nv12_packet.au64PhyAddr[1] = FrameInfo->stVFrame.u64PhyAddr[1];
    stSrc_nv12_packet.au64PhyAddr[2] = FrameInfo->stVFrame.u64PhyAddr[2];

    stSrc_nv12_packet.au64VirAddr[0] = (HI_U64) HI_MPI_SYS_Mmap(FrameInfo->stVFrame.u64PhyAddr[0],
                                                                             u32DstBlkSize / 2);

    stSrc_nv12_packet.au64VirAddr[1] = stSrc_nv12_packet.au64VirAddr[0] + FrameInfo->stVFrame.u32Stride[0] * FrameInfo->stVFrame.u32Height;
    stSrc_nv12_packet.au64VirAddr[2] = stSrc_nv12_packet.au64VirAddr[1] + (HI_U64) 1;

    stSrc_nv12_packet.au32Stride[0] = FrameInfo->stVFrame.u32Stride[0];
    stSrc_nv12_packet.au32Stride[1] = FrameInfo->stVFrame.u32Stride[0];
    stSrc_nv12_packet.au32Stride[2] = 0;

    stSrc_nv12_packet.u32Width = FrameInfo->stVFrame.u32Width;
    stSrc_nv12_packet.u32Height = FrameInfo->stVFrame.u32Height;

    s32Ret = HI_MPI_IVE_CSC(&IveHandle, &stSrc_nv12_packet, &stDst_bgr_packet, &stCscCtrl, bInstant);
    if (s32Ret != HI_SUCCESS){
        printf("HI_MPI_IVE_CSC failed with error code %#x\n", s32Ret);
    }

    s32Ret = HI_MPI_IVE_Query(IveHandle, &bFinish, HI_TRUE);
    if (s32Ret != HI_SUCCESS){
        printf("HI_MPI_IVE_Query failed with error code %#x\n", s32Ret);
    }

    HI_MPI_SYS_MmzFlushCache(stDst_bgr_packet.au64PhyAddr[0],(void **) stDst_bgr_packet.au64VirAddr[0], u32DstBlkSize);

    memcpy((void *) (dst), (void *) stDst_bgr_packet.au64VirAddr[0], u32DstBlkSize);
    HI_MPI_SYS_Munmap((HI_VOID *) stSrc_nv12_packet.au64VirAddr[0], u32DstBlkSize / 2);

    return HI_SUCCESS;
}

void NV12toBGR(uint8_t* nv12, int width, int height, uint8_t* bgr) {
    int ySize = width * height;
    uint8_t* y = nv12;
    uint8_t* uv = nv12 + ySize;

    for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            int yIndex = i * width + j;
            int uvIndex = (i / 2) * width + (j & ~1);

            int yVal = y[yIndex] - 16;
            int uVal = uv[uvIndex] - 128;
            int vVal = uv[uvIndex + 1] - 128;

            int b = (298 * yVal + 516 * uVal + 128) >> 8;
            int g = (298 * yVal - 100 * uVal - 208 * vVal + 128) >> 8;
            int r = (298 * yVal + 409 * vVal + 128) >> 8;

            b = b < 0 ? 0 : (b > 255 ? 255 : b);
            g = g < 0 ? 0 : (g > 255 ? 255 : g);
            r = r < 0 ? 0 : (r > 255 ? 255 : r);

            bgr[yIndex * 3] = b;
            bgr[yIndex * 3 + 1] = g;
            bgr[yIndex * 3 + 2] = r;
        }
    }
}

void saveAsJPG(const char* filename, uint8_t* bgr, int width, int height, int quality) {
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    FILE* outfile;
    JSAMPROW row_pointer[1];
    int row_stride;

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    if ((outfile = fopen(filename, "wb")) == NULL) {
        fprintf(stderr, "无法打开输出文件 %s\n", filename);
        return;
    }

    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;

    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, quality, TRUE);
    jpeg_start_compress(&cinfo, TRUE);

    row_stride = width * 3;

    while (cinfo.next_scanline < cinfo.image_height) {
        row_pointer[0] = &bgr[cinfo.next_scanline * row_stride];
        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
    fclose(outfile);
    jpeg_destroy_compress(&cinfo);
}

static void YUVtoJPG(uint8_t* yuvData, int width, int height, const char* outputPath, int quality) {
    uint8_t* rgb = (uint8_t*)malloc(width * height * 3);
    NV12toBGR(yuvData, width, height, rgb);
    saveAsJPG(outputPath, rgb, width, height, quality);
    free(rgb);
}

static uint64_t get_current_timestamp_ms() {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000;;
}

int save_snap_info_to_ini(const NetworkConfigStorageSnapParam *snap_info)
{
    if ( !snap_info) {
        return -1;
    }

    const char *section = "snap_config";
    const char *keys[50];  // 足够大的数组来存储所有键
    const void *values[50];
    int types[50];
    int count = 0;
    char key_buffer[50][64]; // 为动态生成的键名存储空间

    keys[count] = "timing_snap_enable";
    values[count] = &snap_info->timing_snap_enable;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    keys[count] = "image_format";
    values[count] = &snap_info->timing_snap.image_format;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    keys[count] = "resolution";
    values[count] = &snap_info->timing_snap.resolution;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    keys[count] = "interval";
    values[count] = &snap_info->timing_snap.interval;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    keys[count] = "quality";
    values[count] = &snap_info->timing_snap.quality;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    keys[count] = "num";
    values[count] = &snap_info->timing_snap.num;
    types[count] = VALUE_TYPE_INTEGER;
    count++;

    printf("================================save count: %d\n", count);
    return write_config_to_ini(section, keys, values, types, count);
}

int load_snap_info_from_ini(NetworkConfigStorageSnapParam *snap_info)
{
    if (!snap_info) {
        return -1;
    }

    printf("================================line: %d\n", __LINE__);

    const char *section = "snap_config";
    // 设置默认值
    NetworkConfigStorageSnapParam default_snap_info = {
       .timing_snap_enable = 0,
       .timing_snap.image_format = 0,
       .timing_snap.resolution = 0,
       .timing_snap.interval = 1,
       .timing_snap.quality = 0,
       .timing_snap.num = 1
    };

    // 复制默认值到输出参数
    memcpy(snap_info, &default_snap_info, sizeof(NetworkConfigStorageSnapParam));

    const char *keys[50];
    void *values[50];
    int types[50];
    const void *defaults[50];
    int count = 0;
    int i;
    char key_buffer[50][64];

    keys[count] = "timing_snap_enable";
    values[count] = &snap_info->timing_snap_enable;
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap_enable;
    count++;

    keys[count] = "image_format";
    values[count] = &snap_info->timing_snap.image_format;
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap.image_format;
    count++;

    keys[count] = "resolution";
    values[count] = &snap_info->timing_snap.resolution; 
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap.resolution;
    count++;

    keys[count] = "interval";
    values[count] = &snap_info->timing_snap.interval;
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap.interval;
    count++;

    keys[count] = "quality";
    values[count] = &snap_info->timing_snap.quality ;
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap.quality;
    count++;

    keys[count] = "num";
    values[count] = &snap_info->timing_snap.num;
    types[count] = VALUE_TYPE_INTEGER;
    defaults[count] = &default_snap_info.timing_snap.num;
    count++;

    printf("================================read count: %d\n", count);
    int ret = read_config_from_ini(section, keys, values, types, defaults, count);
    if (ret != 0) {
        fprintf(stderr, "Error: read_config_from_ini failed with code %d\n", ret);
    }
    return ret;
} 


// 抓拍线程函数
void* capture_thread(void *arg) {
    CaptureInfo_S *state = (CaptureInfo_S *)arg;
    int s32Ret;
    VIDEO_FRAME_INFO_S astFrame[2];
    HI_S32 s32MilliSec = 2000;
    HI_S32 s32VpssGrp = 0;
    HI_S32 as32VpssChn[] = {0, 1};
    HI_U32 remainUVSize = 0;
    uint64_t last_capture_time_ms = 0; // 添加上次抓拍时间戳
    char output_path[256]; // 文件路径缓冲区
    int quality = 100; // 默认质量
    const char* image_save_dir = "/mnt/snap_files"; // 图片保存目录

    // 检查并创建目录
    if (access(image_save_dir, F_OK) != 0) {
        if (errno == ENOENT) {
            if (mkdir(image_save_dir, 0755) != 0) {
                perror("Failed to create directory");
                pthread_exit(NULL);
            }
        } else {
            perror("Directory access error");
            pthread_exit(NULL);
        }
    }

    // 不再在线程内加载配置，配置应由外部通过 set_capture_config 更新
    // NetworkConfigStorageSnapParam get_snap_info;
    // memset(&get_snap_info, 0x0, sizeof(NetworkConfigStorageSnapParam));
    // if (load_snap_info_from_ini(&get_snap_info) != 0) {
    //     fprintf(stderr, "Error: Failed to load snap info from ini.\n");
    //     pthread_exit(NULL);
    // }
    // printf("Initial config loaded: enable=%d, interval=%d, num=%d, quality=%d, resolution=%d, image_format=%d\n", get_snap_info.timing_snap_enable,\
    //     get_snap_info.timing_snap.interval, get_snap_info.timing_snap.num, get_snap_info.timing_snap.quality,
    //     get_snap_info.timing_snap.resolution, get_snap_info.timing_snap.image_format);


    while (1) {
        // 获取当前配置
        NetworkConfigStorageSnapParam current_config = get_capture_config(state);
        uint64_t current_time_ms = get_current_timestamp_ms(); // 获取当前时间戳

        // 检查抓拍开关和时间间隔
        if (current_config.timing_snap_enable == 1 && (current_time_ms - last_capture_time_ms >= (uint64_t)current_config.timing_snap.interval * 1000)) {

            printf("Capture triggered: enable=%d, interval=%d, num=%d, quality=%d, resolution=%d, image_format=%d\n",
                   current_config.timing_snap_enable, current_config.timing_snap.interval, current_config.timing_snap.num,
                   current_config.timing_snap.quality, current_config.timing_snap.resolution, current_config.timing_snap.image_format);

            uint64_t cur_time = get_current_timestamp_ms();
            printf("抓拍中...[%llu]\n", cur_time);

            // 设置抓图质量
            switch (current_config.timing_snap.quality) {
                case 0: quality = 50; break; // 低
                case 1: quality = 80; break; // 中
                case 2: quality = 100; break; // 高
                default: quality = 100; break; // 默认为高
            }

            // 设置存储路径和文件名 (使用秒级时间戳)
            snprintf(output_path, sizeof(output_path), "%s/%llu.jpg", image_save_dir, cur_time / 1000);

            // 执行抓拍逻辑
            s32Ret = HI_MPI_VPSS_GetChnFrame(s32VpssGrp, as32VpssChn[1], &astFrame[0], s32MilliSec);
            if (HI_SUCCESS != s32Ret){
                err("HI_MPI_VPSS_GetChnFrame failed with %#x", s32Ret);
                usleep(10 * 1000); // 短暂休眠后重试
                continue; // 获取帧失败则跳过此次循环
            }

            // 计算YUV数据大小
            printf("Frame Info: W=%u, H=%u, Stride=%u, PixelFormat=%d\n",
                   astFrame[0].stVFrame.u32Width, astFrame[0].stVFrame.u32Height,
                   astFrame[0].stVFrame.u32Stride[0], astFrame[0].stVFrame.enPixelFormat);

            if (astFrame[0].stVFrame.enPixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_420) {
                remainUVSize = astFrame[0].stVFrame.u32Width * astFrame[0].stVFrame.u32Height / 2;
            } else if (astFrame[0].stVFrame.enPixelFormat == PIXEL_FORMAT_YVU_SEMIPLANAR_422) {
                remainUVSize = astFrame[0].stVFrame.u32Width * astFrame[0].stVFrame.u32Height;
            } else {
                err("Unsupported pixel format: %d\n", astFrame[0].stVFrame.enPixelFormat);
                goto RELEASE_FRAME; // 不支持的格式，释放帧资源
            }

            HI_U32 expected_size = astFrame[0].stVFrame.u32Height * astFrame[0].stVFrame.u32Stride[0] + remainUVSize; // 使用stride计算Y分量大小
             printf("Debug: Mapping PhyAddr=0x%llx, Size=%u (Stride: %u, UVSize: %u)\n",
                   astFrame[0].stVFrame.u64PhyAddr[0], expected_size, astFrame[0].stVFrame.u32Stride[0], remainUVSize);

            // 内存映射
            HI_U8 *pU8addr = HI_MPI_SYS_Mmap(astFrame[0].stVFrame.u64PhyAddr[0], expected_size);
            if (pU8addr == NULL) {
                err("HI_MPI_SYS_Mmap failed (PhyAddr=0x%llx, Size=%u)\n", astFrame[0].stVFrame.u64PhyAddr[0], expected_size);
                goto RELEASE_FRAME; // MMAP失败则释放帧资源
            }
            printf("Debug: Mmap successful, pU8addr=%p\n", pU8addr);


            printf("Debug: Calling YUVtoJPG with Width=%u, Height=%u, Quality=%d, Path=%s\n",
                   astFrame[0].stVFrame.u32Width, astFrame[0].stVFrame.u32Height, quality, output_path);
            // 调用 YUVtoJPG 保存图片
            YUVtoJPG(pU8addr, astFrame[0].stVFrame.u32Width, astFrame[0].stVFrame.u32Height, output_path, quality);

            // 解除内存映射
            HI_MPI_SYS_Munmap(pU8addr, expected_size);
            printf("Debug: Munmap successful\n");


            uint64_t end_time = get_current_timestamp_ms();
            printf("抓拍over...[%llu], cost %llu ms\n", end_time, (end_time - cur_time));

            // 更新上次抓拍时间
            last_capture_time_ms = current_time_ms; // 使用当前的精确时间戳

        RELEASE_FRAME: // 标签用于统一释放帧资源
            s32Ret = HI_MPI_VPSS_ReleaseChnFrame(s32VpssGrp, as32VpssChn[1], &astFrame[0]);
            if (HI_SUCCESS != s32Ret){
                printf("Error(%#x): HI_MPI_VPSS_ReleaseChnFrame failed, Grp(%d) chn(%d)!\n",s32Ret, s32VpssGrp, as32VpssChn[1]);
            }
        } else {
             // 如果不满足抓拍条件，短暂休眠避免CPU空转
             usleep(100 * 1000); // 休眠100ms
        }
    }
    return NULL;
}